#!/usr/bin/env python
# lsusb.py
# Displays your USB devices in reasonable form.
# (c) Kurt Garloff <garloff@suse.de>, 2/2009, GPL v2 or v3.
# (c) Kurt Garloff <kurt@garloff.de>, 9/2013, GPL v2 or v3.
# Usage: See usage()

import os, sys, re, getopt

# from __future__ import print_function

# Global options
showint = False
showhubint = False
noemptyhub = False
nohub = False
warnsort = False
showeps = False

prefix = "/sys/bus/usb/devices/"
usbids = os.path.join(os.path.dirname(__file__),'usb.ids')
#~ "/usr/share/usb.ids"

esc = chr(27)
norm = esc + "[0;0m"
bold = esc + "[0;1m"
red =  esc + "[0;31m"
green= esc + "[0;32m"
amber= esc + "[0;33m"
blue = esc + "[0;34m"

cols = ("", "", "", "", "", "")

def readattr(path, name):
    "Read attribute from sysfs and return as string"
    f = open(prefix + path + "/" + name);
    return f.readline().rstrip("\n");

def readlink(path, name):
    "Read symlink and return basename"
    return os.path.basename(os.readlink(prefix + path + "/" + name));

class UsbClass:
    "Container for USB Class/Subclass/Protocol"
    def __init__(self, cl, sc, pr, str = ""):
        self.pclass = cl
        self.subclass = sc
        self.proto = pr
        self.desc = str
    def __repr__(self):
        return 'UsbClass' +str((self.pclass,self.subclass,self.proto,self.desc))
    def __cmp__(self, oth):
        # Works only on 64bit systems:
        #return self.pclass*0x10000+self.subclass*0x100+self.proto \
        #   - oth.pclass*0x10000-oth.subclass*0x100-oth.proto
        if self.pclass != oth.pclass:
            return self.pclass - oth.pclass
        if self.subclass != oth.subclass:
            return self.subclass - oth.subclass
        return self.proto - oth.proto

class UsbVendor:
    "Container for USB Vendors"
    def __init__(self, vid, vname = ""):
        self.vid = vid
        self.vname = vname
    def __repr__(self):
        return 'UsbVendor'+str((self.vid,self.vname))
    def __cmp__(self, oth):
        return self.vid - oth.vid

class UsbProduct:
    "Container for USB VID:PID devices"
    def __init__(self, vid, pid, pname = ""):
        self.vid = vid
        self.pid = pid
        self.pname = pname
    def __repr__(self):
        return 'UsbProduct'+str((self.vid,self.pid,self.pname))
    def __cmp__(self, oth):
        # Works only on 64bit systems:
        # return self.vid*0x10000 + self.pid \
        #   - oth.vid*0x10000 - oth.pid
        if self.vid != oth.vid:
            return self.vid - oth.vid
        return self.pid - oth.pid

usbvendors = []
usbproducts = []
usbclasses = []

def ishexdigit(str):
    "return True if all digits are valid hex digits"
    for dg in str:
        if not dg.isdigit() and not dg in 'abcdef':
            return False
    return True

def parse_usb_ids():
    "Parse /usr/share/usb.ids and fill usbvendors, usbproducts, usbclasses"
    id = 0
    sid = 0
    mode = 0
    strg = ""
    cstrg = ""
    for ln in file(usbids, "r").readlines():
        if ln[0] == '#':
            continue
        ln = ln.rstrip('\n')
        if len(ln) == 0:
            continue
        if ishexdigit(ln[0:4]):
            mode = 0
            id = int(ln[:4], 16)
            usbvendors.append(UsbVendor(id, ln[6:]))
            continue
        if ln[0] == '\t' and ishexdigit(ln[1:3]):
            sid = int(ln[1:5], 16)
            # USB devices
            if mode == 0:
                usbproducts.append(UsbProduct(id, sid, ln[7:]))
                continue
            elif mode == 1:
                nm = ln[5:]
                if nm != "Unused":
                    strg = cstrg + ":" + nm
                else:
                    strg = cstrg + ":"
                usbclasses.append(UsbClass(id, sid, -1, strg))
                continue
        if ln[0] == 'C':
            mode = 1
            id = int(ln[2:4], 16)
            cstrg = ln[6:]
            usbclasses.append(UsbClass(id, -1, -1, cstrg))
            continue
        if mode == 1 and ln[0] == '\t' and ln[1] == '\t' and ishexdigit(ln[2:4]):
            prid = int(ln[2:4], 16)
            usbclasses.append(UsbClass(id, sid, prid, strg + ":" + ln[6:]))
            continue
        mode = 2

def main():
    parse_usb_ids()
    print('Usb Class List')
    for i in usbclasses:
        print(i)

    #~ print usbproducts
    #~ print usbvendors

# Entry point
if __name__ == "__main__":
    main()


